package org.coco.mvc.handle;

import org.coco.core.BeanContainer;
import org.coco.core.annotation.ResponseBody;
import org.coco.mvc.RequestProcessorChain;
import org.coco.mvc.annotation.RequestParam;
import org.coco.mvc.render.impl.InternalErrorResultRender;
import org.coco.mvc.render.impl.JsonResultRender;
import org.coco.mvc.render.impl.ResourceNotFoundResultRender;
import org.coco.mvc.render.impl.ViewResultRender;
import org.coco.util.CommonUtil;
import org.coco.util.ValidationUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 专门处理GET请求的Handle
 */
public class GetHandleMapping {

    private Map<Class<?>, Object> map = null;


    public GetHandleMapping() {
        this.map = BeanContainer.getInstance().getMap();
    }

    public boolean doGet(Map<String, HandleMapping> requestMappingMap, String requestPath,Map<String,Object> paramsMap,
                         RequestProcessorChain requestProcessorChain) throws Exception{
        HandleMapping handleMappingResult = requestMappingMap.get(requestPath);
        //从获取到的handleMappingResult得到需要执行那个类的那个方法
        Class<?> clazz = handleMappingResult.getClazz();
        String invokeMethodName = handleMappingResult.getMethod();
        //Method method = clazz.getMethod(invokeMethodName);
        //获取该类所有的方法
        Method[] methods = clazz.getMethods();
        boolean isHaveMethod = false;
        for(Method method : methods) {
            //排除Object类中一些自带的方法
            if(CommonUtil.isMethodName(method)) {
                continue;
            }
            List paramValueList = new ArrayList();
            if(invokeMethodName.equals(method.getName())) {
                isHaveMethod = true;
                Object result = this.map.get(clazz);
                //获取该方法中的所有参数，并且解析@RequestParam注解
                Parameter[] parameters = method.getParameters();
                if(!ValidationUtil.isEmpty(parameters)) {
                    for(Parameter parameter : parameters) {
                        //遍历参数，如果和请求的参数对的上的话就赋值，没有的话就设置为默认值
                        //判断一下该参数是否有@RequestParam注解，没有的话就抛出异常
                        if(parameter.isAnnotationPresent(RequestParam.class)){
                            //该参数有@RequestParam注解，然后获取请求路径携带的参数
                            RequestParam annotationRequestParam = parameter.getAnnotation(RequestParam.class);
                            //得到该注解的值
                            String annotationRequestParamValue = annotationRequestParam.value();
                            //判断@RequestParam注解中的值是否存在之前保存到Map中的值
                            if(ValidationUtil.isEmpty(annotationRequestParamValue)) {
                                //如果我们没有在@RequestParam设定参数名称，那么就使用默认的
                                if(paramsMap.containsKey(parameter.getName())) {
                                    //如果存在这个参数,那么就对这个参数赋值
                                    Object object = paramsMap.get(parameter.getName());
                                    //将所有参数的值放入到这个集合中去
                                    paramValueList.add(object);
                                }else {
                                    //如果参数名称对不上或者没有，直接抛出异常
                                    requestProcessorChain.setResultRender(new InternalErrorResultRender(new RuntimeException("参数类型不对")));
                                    return true;
                                }
                            }else {
                                //说明注解上设置了值，也就是参数名称
                                if(paramsMap.containsKey(annotationRequestParamValue)) {
                                    //如果存在这个参数,那么就对这个参数赋值
                                    Object object = paramsMap.get(parameter.getName());
                                    //将所有参数的值放入到这个集合中去
                                    paramValueList.add(object);
                                }else {
                                    //注解上的值与参数名称对不上
                                    requestProcessorChain.setResultRender(new InternalErrorResultRender(new RuntimeException("参数类型不对")));
                                    return true;
                                }
                            }
                        }else {
                            //参数没有携带@RequestParam注解
                            //todo 需要判断下是否能有别的参数，比如HttpServletRequest,HttpSession参数就不需要有注解了等
                            //todo 暂时这里就不做任何处理了
                            requestProcessorChain.setResultRender(
                                    new InternalErrorResultRender(new RuntimeException("method "+method.getName()+" need params: "+ parameter.getName())));
                            return true;
                        }
                    }
                }
                Object methodReturnValue = null;
                if(ValidationUtil.isEmpty(paramValueList)) {
                    //说明该方法没有参数
                    //执行目标方法并获取方法的返回值
                    methodReturnValue = method.invoke(result);
                }else {
                    List<Object> paramValue = new ArrayList<>();
                    //说明该方法是有参数的
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    int parameterTypesLength = parameterTypes.length;
                    for(int i = 0; i < parameterTypesLength; i++) {
                        if(parameterTypes[i] == String.class) {
                            String value = (String)paramValueList.get(i);
                            paramValue.add(value);
                        }else if(parameterTypes[i] == int.class || parameterTypes[i] == Integer.class) {
                            Integer value = Integer.parseInt((String)paramValueList.get(i));
                            paramValue.add(value);
                        }else if(parameterTypes[i] == float.class || parameterTypes[i] == Float.class) {
                            Float value = Float.parseFloat((String)paramValueList.get(i));
                            paramValue.add(value);
                        }else if(parameterTypes[i] == boolean.class || parameterTypes[i] == Boolean.class) {
                            Boolean value = Boolean.parseBoolean((String)paramValueList.get(i));
                            paramValue.add(value);
                        }else if(parameterTypes[i] == double.class || parameterTypes[i] == Double.class) {
                            Double value = Double.parseDouble((String)paramValueList.get(i));
                            paramValue.add(value);
                        }
                    }
                    //执行目标方法并获取方法的返回值
                    methodReturnValue = method.invoke(result,paramValue.toArray());
                }
                //查看该方法上或者该类上是否有@ResponseBody注解，如果有就返回JSOn数据给客户
                if(clazz.isAnnotationPresent(ResponseBody.class) || method.isAnnotationPresent(ResponseBody.class)) {
                    requestProcessorChain.setResultRender(new JsonResultRender(methodReturnValue));
                }else {
                    //说明该方法需要匹配一个页面返回
                    //暂时这里就不做任何处置,比如返回 xx 那就返回 xx.html
                    requestProcessorChain.setResultRender(new ViewResultRender(methodReturnValue));
                }
            }
        }
        if(!isHaveMethod) {
            //没有找到这个方法
            requestProcessorChain.setResultRender(new ResourceNotFoundResultRender());
        }
        return false;
    }



}
